﻿using System;
using System.Threading;
using fastCSharp;
using fastCSharp.code.cSharp;
using fastCSharp.net;

namespace diantou.webSocket.exam
{
    /// <summary>
    /// 考试日志
    /// </summary>
    [fastCSharp.code.cSharp.webSocket]
    partial class log : user<log>
    {
        /// <summary>
        /// 最大接收消息大小
        /// </summary>
        protected override int maxMessageSize
        {
            get
            {
                return (1 << 20) - (2 + 8 + 4);
            }
        }
        /// <summary>
        /// 过期处理
        /// </summary>
        private void expired()
        {
            userId = sessionId = 0;
        }
        /// <summary>
        /// 是否触发会话更新通知
        /// </summary>
        private int isSessionChange;
        /// <summary>
        /// 会话更新通知
        /// </summary>
        /// <param name="sessionId"></param>
        private void onSessionChange(fastCSharp.net.returnValue<int> sessionId)
        {
            if (this.userId != 0 && !IsClose)
            {
                if (sessionId.Type == returnValue.type.Success && sessionId != this.sessionId)
                {
                    expired();
                    send(verifyExpiredData);
                }
                else fastCSharp.threading.timerTask.Default.Add(setSessionChange, date.NowSecond.AddSeconds(5));
            }
        }
        /// <summary>
        /// 设置会话更新通知
        /// </summary>
        private void setSessionChange()
        {
            if (this.userId != 0 && !IsClose) pub.AnswerCacheClient.sessionChange(this.userId, this.sessionId, onSessionChange);
        }
        /// <summary>
        /// 测试日志问题标识集合
        /// </summary>
        private subArray<int> logProblemIds;
        /// <summary>
        /// 是否存在日志
        /// </summary>
        private bool isLog;
        /// <summary>
        /// 考试日志消息处理
        /// </summary>
        /// <param name="data"></param>
        protected unsafe override void onMessage(subArray<byte> data)
        {
            byte[] returnData = exceptionData;
            int userId;
            try
            {
                if (data.Count != 0)
                {
                    fixed (byte* dataFixed = data.UnsafeArray)
                    {
                        byte* dataStart = dataFixed + data.StartIndex;
                        switch (*dataStart)
                        {
                            case 0: returnData = null; return;
                            case 1:
                                if (data.Count == 1 + 4 + 4 + 4)
                                {
                                    userId = *(int*)(dataStart + 1);
                                    int sessionId = *(int*)(dataStart + 5);
                                    uint verifyCode = *(uint*)(dataStart + 9);
                                    if (userId > 0 && sessionId > 0 && verifyCode != 0)
                                    {
                                        if (((userId ^ this.userId) | (sessionId ^ this.sessionId)) == 0)
                                        {
                                            returnData = successData;
                                            return;
                                        }
                                        subArray<int> logProblemIds = default(subArray<int>);
                                        bool isLog = false;
                                        switch (pub.AnswerCacheClient.checkVerifyCode(userId, sessionId, verifyCode, ref isLog, ref logProblemIds).Value)
                                        {
                                            case 1:
                                                returnData = successData;
                                                this.userId = userId;
                                                this.sessionId = sessionId;
                                                this.isLog |= isLog;
                                                foreach (int problemId in logProblemIds)
                                                {
                                                    if (this.logProblemIds.IndexOf(problemId) == -1) this.logProblemIds.Add(problemId);
                                                }
                                                if (Interlocked.CompareExchange(ref isSessionChange, 0, 1) == 0) setSessionChange();
                                                return;
                                            case 2: returnData = verifyExpiredData; return;
                                            default: returnData = verifyErrorData; return;
                                        }
                                    }
                                }
                                returnData = errorData;
                                return;
                            case 2:
                                if ((userId = this.userId) == 0)
                                {
                                    returnData = null;
                                    Console.WriteLine("Web Socket User Error");
                                }
                                else
                                {
                                    int count = *(byte*)(dataStart + 1);
                                    if (count > 0 && data.Count >= 2 + count * (4 + 1 + 2))
                                    {
                                        diantou.examLogServer.examLog[] logs = new examLogServer.examLog[count];
                                        count = 0;
                                        for (buffer buffer = new buffer(dataStart + 2, dataStart + data.Count); buffer.Length >= 4 + 1 + 2; )
                                        {
                                            examLogServer.examLog log = new examLogServer.examLog { UserId = userId };
                                            log.Times = buffer.UInt();
                                            log.Type = (diantou.dataModel.examLog.type)buffer.Byte();
                                            log.Index = buffer.Short();
                                            switch (log.Type)
                                            {
                                                case dataModel.examLog.type.SetLoad:
                                                case dataModel.examLog.type.GetQuestion:
                                                case dataModel.examLog.type.SetRadioAnswer:
                                                case dataModel.examLog.type.SetMultipleAnswer:
                                                    break;
                                                case dataModel.examLog.type.ShowAnswer:
                                                case dataModel.examLog.type.SetQuestion:
                                                    if ((log.Content = buffer.UShortString()) == null)
                                                    {
                                                        returnData = errorData;
                                                        Console.WriteLine("Web Socket Log Error " + log.Type.ToString());
                                                        return;
                                                    }
                                                    break;
                                                default:
                                                    returnData = errorData;
                                                    Console.WriteLine("Web Socket Log Error " + log.Type.ToString());
                                                    return;
                                            }
                                            logs[count++] = log;
                                            if (count == logs.Length)
                                            {
                                                if (buffer.Length == 0)
                                                {
                                                    fastCSharp.net.returnValue<bool> isLog = diantou.examLogServer.tcpCall.examLog.append(userId, this.sessionId, logs);
                                                    if (isLog.Type == returnValue.type.Success)
                                                    {
                                                        if (isLog.Value)
                                                        {
                                                            returnData = null;
                                                            if (!isLog && pub.AnswerCacheClient.setLog(userId).Type == returnValue.type.Success) isLog = true;
                                                        }
                                                        else
                                                        {
                                                            expired();
                                                            returnData = verifyExpiredData;
                                                        }
                                                    }
                                                }
                                                return;
                                            }
                                        }
                                    }
                                    Console.WriteLine("Web Socket Log Data Error " + data.Count.toString());
                                    returnData = errorData;
                                }
                                return;
                            case 3:
                                if ((userId = this.userId) == 0)
                                {
                                    returnData = null;
                                    Console.WriteLine("Web Socket User Error");
                                }
                                else
                                {
                                    int count = *(byte*)(dataStart + 1);
                                    if (count > 0 && data.Count >= 2 + count * (4 + 1))
                                    {
                                        subArray<int> logProblemIds = default(subArray<int>);
                                        diantou.examLogServer.examJudgeLog[] logs = new examLogServer.examJudgeLog[count];
                                        count = 0;
                                        for (buffer buffer = new buffer(dataStart + 2, dataStart + data.Count); buffer.Length >= 4 + 1; )
                                        {
                                            examLogServer.examJudgeLog log = new examLogServer.examJudgeLog { UserId = userId };
                                            log.Times = buffer.UInt();
                                            switch (log.Type = (diantou.dataModel.examJudgeLog.type)buffer.Byte())
                                            {
                                                case dataModel.examJudgeLog.type.LoadAce:
                                                    if (buffer.Length >= 4 + 1 + 2)
                                                    {
                                                        log.StartRow = (int)buffer.UInt();
                                                        log.StartColumn = buffer.Byte();
                                                        string content = buffer.UShortString();
                                                        if (content != null)
                                                        {
                                                            log.Content = new string[] { content };
                                                            if (this.logProblemIds.IndexOf(log.StartRow) == -1 && logProblemIds.IndexOf(log.StartRow) == -1) logProblemIds.Add(log.StartRow);
                                                            break;
                                                        }
                                                    }
                                                    Console.WriteLine("Web Socket JudgeLog Error " + log.Type.ToString());
                                                    returnData = errorData;
                                                    return;
                                                case dataModel.examJudgeLog.type.SetLanguage:
                                                    log.StartColumn = buffer.Byte();
                                                    break;
                                                case dataModel.examJudgeLog.type.Judge: break;
                                                case dataModel.examJudgeLog.type.OnJudge:
                                                    if (buffer.Length >= 2)
                                                    {
                                                        string content = buffer.UShortString();
                                                        if (content != null)
                                                        {
                                                            log.Content = new string[] { content };
                                                            break;
                                                        }
                                                    }
                                                    Console.WriteLine("Web Socket JudgeLog Error " + log.Type.ToString());
                                                    returnData = errorData;
                                                    return;
                                                case dataModel.examJudgeLog.type.insertText:
                                                case dataModel.examJudgeLog.type.removeText:
                                                    if (buffer.Length >= 4 * 2 + 2)
                                                    {
                                                        log.StartRow = buffer.UShort();
                                                        log.StartColumn = buffer.UShort();
                                                        log.EndRow = buffer.UShort();
                                                        log.EndColumn = buffer.UShort();
                                                        string content = buffer.UShortString();
                                                        if (content != null)
                                                        {
                                                            log.Content = new string[] { content };
                                                            break;
                                                        }
                                                    }
                                                    Console.WriteLine("Web Socket JudgeLog Error " + log.Type.ToString());
                                                    returnData = errorData;
                                                    return;
                                                case dataModel.examJudgeLog.type.insertLines:
                                                case dataModel.examJudgeLog.type.removeLines:
                                                    if (buffer.Length >= 4 * 2 + 2)
                                                    {
                                                        log.StartRow = buffer.UShort();
                                                        log.StartColumn = buffer.UShort();
                                                        log.EndRow = buffer.UShort();
                                                        log.EndColumn = buffer.UShort();
                                                        string[] contents = new string[buffer.UShort()];
                                                        for (int index = 0; index != contents.Length; ++index)
                                                        {
                                                            string content = buffer.UShortString();
                                                            if (content == null)
                                                            {
                                                                returnData = errorData;
                                                                return;
                                                            }
                                                            contents[index] = content;
                                                        }
                                                        log.Content = contents;
                                                        break;
                                                    }
                                                    Console.WriteLine("Web Socket JudgeLog Error " + log.Type.ToString());
                                                    returnData = errorData;
                                                    return;
                                                default:
                                                    Console.WriteLine("Web Socket JudgeLog Error " + log.Type.ToString());
                                                    returnData = errorData;
                                                    return;
                                            }
                                            logs[count++] = log;
                                            if (count == logs.Length)
                                            {
                                                if (buffer.Length == 0)
                                                {
                                                    fastCSharp.net.returnValue<bool> isLog = diantou.examLogServer.tcpCall.examJudgeLog.append(userId, this.sessionId, logs);
                                                    if (isLog.Type == returnValue.type.Success)
                                                    {
                                                        if (isLog.Value)
                                                        {
                                                            returnData = null;
                                                            if (logProblemIds.Count != 0 && pub.AnswerCacheClient.setLogProblemIds(userId, logProblemIds).Type == returnValue.type.Success)
                                                            {
                                                                this.logProblemIds.Add(logProblemIds);
                                                            }
                                                        }
                                                        else
                                                        {
                                                            expired();
                                                            returnData = verifyExpiredData;
                                                        }
                                                    }
                                                }
                                                return;
                                            }
                                        }
                                    }
                                    Console.WriteLine("Web Socket JudgeLog Data Error " + data.Count.toString());
                                    returnData = errorData;
                                }
                                return;
                            default:
                                Console.WriteLine("Web Socket Type Error");
                                break;
                        }
                    }
                }
                returnData = errorData;
            }
            finally { if (returnData != null) send(returnData); }
        }
    }
}
